/*
  This file is part of 'Trivial chess'.

  'Trivial chess' is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  'Trivial chess' is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with 'Trivial chess'.  If not, see <http://www.gnu.org/licenses/>.
*/

/* SVN FILE: $Id$ */
/**
 * @author         $Author$
 * @version        $Rev$
 * @lastrevision   $Date$
 * @filesource     $URL$
 */

#ifndef MANABSTRACT_H_
#define MANABSTRACT_H_

#include <boost/algorithm/string.hpp>

#include "../EnumAbstract.h"

template<template<class, class, typename> class Man, class C, class P, typename Int>
class ManAbstract : public EnumAbstract<Man<Color, Piece, Int>, Int> {
public:
	typedef C Color;
	typedef P Piece;

	static const Int COUNT = 12;
	static const Man<Color, Piece, Int> WHITE_PAWN() {
		return Man<Color, Piece, Int>(Color::WHITE(), Piece::PAWN());
	}
	static const Man<Color, Piece, Int> BLACK_PAWN() {
		return Man<Color, Piece, Int>(Color::BLACK(), Piece::PAWN());
	}
	static const Man<Color, Piece, Int> WHITE_BISHOP() {
		return Man<Color, Piece, Int>(Color::WHITE(), Piece::BISHOP());
	}
	static const Man<Color, Piece, Int> BLACK_BISHOP() {
		return Man<Color, Piece, Int>(Color::BLACK(), Piece::BISHOP());
	}
	static const Man<Color, Piece, Int> WHITE_KNIGHT() {
		return Man<Color, Piece, Int>(Color::WHITE(), Piece::KNIGHT());
	}
	static const Man<Color, Piece, Int> BLACK_KNIGHT() {
		return Man<Color, Piece, Int>(Color::BLACK(), Piece::KNIGHT());
	}
	static const Man<Color, Piece, Int> WHITE_ROOK() {
		return Man<Color, Piece, Int>(Color::WHITE(), Piece::ROOK());
	}
	static const Man<Color, Piece, Int> BLACK_ROOK() {
		return Man<Color, Piece, Int>(Color::BLACK(), Piece::ROOK());
	}
	static const Man<Color, Piece, Int> WHITE_QUEEN() {
		return Man<Color, Piece, Int>(Color::WHITE(), Piece::QUEEN());
	}
	static const Man<Color, Piece, Int> BLACK_QUEEN() {
		return Man<Color, Piece, Int>(Color::BLACK(), Piece::QUEEN());
	}
	static const Man<Color, Piece, Int> WHITE_KING() {
		return Man<Color, Piece, Int>(Color::WHITE(), Piece::KING());
	}
	static const Man<Color, Piece, Int> BLACK_KING() {
		return Man<Color, Piece, Int>(Color::BLACK(), Piece::KING());
	}
public:
	static const Man<Color, Piece, Int> BEGIN() {
		return Man<Color, Piece, Int>::WHITE_PAWN();
	}

	static const Man<Color, Piece, Int> RBEGIN() {
		return Man<Color, Piece, Int>::BLACK_KING();
	}
public:
	const Color color() const;
	const Piece piece() const;
	void setColor(const Color color);
	void setPiece(const Piece piece);
public:
	bool isWhite()  const { return this->me_c().color().isWhite(); }
	bool isBlack()  const { return this->me_c().color().isBlack(); }

	bool isPawn()   const { return this->me_c().piece().isPawn(); }
	bool isBishop() const { return this->me_c().piece().isBishop(); }
	bool isKnight() const { return this->me_c().piece().isKnight(); }
	bool isRook()   const { return this->me_c().piece().isRook(); }
	bool isQueen()  const { return this->me_c().piece().isQueen(); }
	bool isKing()   const { return this->me_c().piece().isKing(); }

	bool isMinor()  const { return this->me_c().piece().isMinor(); }
	bool isMajor()  const { return this->me_c().piece().isMajor(); }
	bool isSlider() const { return this->me_c().piece().isSlider(); }
	bool isLeaper() const { return this->me_c().piece().isLeaper(); }

	bool isWhitePawn() const {
		return this->me_c() == Man<Color, Piece, Int>::WHITE_PAWN();
	}
	bool isBlackPawn() const {
		return this->me_c() == Man<Color, Piece, Int>::BLACK_PAWN();
	}
	bool isWhiteBishop() const {
		return this->me_c() == Man<Color, Piece, Int>::WHITE_BISHOP();
	}
	bool isBlackBishop() const {
		return this->me_c() == Man<Color, Piece, Int>::BLACK_BISHOP();
	}
	bool isWhiteKnight() const {
		return this->me_c() == Man<Color, Piece, Int>::WHITE_KNIGHT();
	}
	bool isBlackKnight() const {
		return this->me_c() == Man<Color, Piece, Int>::BLACK_KNIGHT();
	}
	bool isWhiteRook() const {
		return this->me_c() == Man<Color, Piece, Int>::WHITE_ROOK();
	}
	bool isBlackRook() const {
		return this->me_c() == Man<Color, Piece, Int>::BLACK_ROOK();
	}
	bool isWhiteQueen() const {
		return this->me_c() == Man<Color, Piece, Int>::WHITE_QUEEN();
	}
	bool isBlackQueen() const {
		return this->me_c() == Man<Color, Piece, Int>::BLACK_QUEEN();
	}
	bool isWhiteKing() const {
		return this->me_c() == Man<Color, Piece, Int>::WHITE_KING();
	}
	bool isBlackKing() const {
		return this->me_c() == Man<Color, Piece, Int>::BLACK_KING();
	}

public:
	void fromColorAndPiece(const Color c, const Piece p) {
		this->me().setColor(c);
		this->me().setPiece(p);
	}

	std::string toStr() const {
		if ( this->me_c().isNil() )
			return "-";

		std::string ret = this->me_c().piece().toStr();
		if ( this->me_c().color().isWhite() ) {
			boost::to_upper(ret);
		}

		return ret;
	}

	void fromStr(const std::string str) {
		if ( "-" == str ) {
			this->me() = Man<Color, Piece, Int>::NIL();
			return;
		}

		const std::string newStr = boost::to_lower_copy(str);
		if ( newStr == str )
			this->me().setColor(Color::BLACK());
		else
			this->me().setColor(Color::WHITE());

		Piece p;
		p.fromStr(newStr);
		this->me().setPiece(p);
	}

};

#endif /* MANABSTRACT_H_ */
